#!/usr/bin/env python3

import os
from eeprom  import Programmer
from tkinter import *
from tkinter import messagebox, filedialog
from tkinter.ttk import *

print("tkinter版本:{}".format(TkVersion))

mainTitle = 'EEPROM编程器'

'''
格式 芯片名 编号 是否可以写入
    27C16 2716
16      0x007ff     2048
32      0x00fff     4096
64      0x01fff     8192
128     0x03fff     16384
256     0x07fff     32768
512     0x0ffff     65536
010     0x1ffff     131072
020     0x3ffff     262144
040     0x7ffff     524287
080     0xfffff     1048576
'''
radio27_24P = [
    ("27C16", '2716', 0x7ff, 0),
    ("27C32", '2732', 0xfff,0)
]

radio27_28P = [
    ("27C64  ", '2764', 0x1fff, 0),
    ("27C128", '27128', 0x3fff, 0),
    ("27C256", '27256', 0x7fff, 0),
    ("27C512", '27512', 0xffff, 0)
]

radio28 = [
    ("AT28C64B", '2864', 0x1fff, 1),
    ("AT28C256", '28256', 0x7fff, 1)
]

radio32 = [
    ("29C010", '29010', 0x1ffff, 1),
    ("29C020", '29020', 0x3ffff, 1),
    ("29C040", '29040', 0x7ffff, 1),
]

radio32_page128 = [
    ("29C010", '29011', 0x1ffff, 1),
    ("29C020", '29021', 0x3ffff, 1),
    ("29C040", '29041', 0x7ffff, 1)
]

chips = []
chips = radio27_24P + radio27_28P + radio28 + radio32 + radio32_page128
#所有芯片类型
print(chips)


chip_name = ''
chip_id = ''
chip_rw = ''
chip_endAddress = 0

class Progressbox(Toplevel):
    def __init__(self, root=None, title='请稍等 !', activity='读取中...', value=0):
        Toplevel.__init__(self, root)
        self.__step=IntVar()
        self.__step.set(value)
        self.__act=StringVar()
        self.__act.set(activity)
        self.title(title)
        self.resizable(width=False, height=False)
        self.transient(root)
        self.grab_set()
        Label(self, textvariable=self.__act).pack(padx=20, pady=10)
        Progressbar(self, orient=HORIZONTAL, length=200, 
                variable=self.__step, mode='determinate').pack(
                padx=10, pady=10)
        self.update_idletasks()

    def setactivity(self, activity):
        self.__act.set(activity)
        self.update_idletasks()

    def setvalue(self, value):
        self.__step.set(value)
        self.update_idletasks()


def showContent():
    eeprom=Programmer()
    eeprom.connect340()
    if not eeprom.is_open:
        messagebox.showerror('异常', '连接编程器异常')
        return

    contentWindow=Toplevel(mainWindow)
    contentWindow.title('EEPROM READER')
    contentWindow.minsize(200, 110)
    contentWindow.resizable(width=False, height=True)
    contentWindow.transient(mainWindow)
    contentWindow.grab_set()

    l=Listbox(contentWindow, font='TkFixedFont', height=36, width=72)
    l.pack(side='left', fill=BOTH)
    s=Scrollbar(contentWindow, orient=VERTICAL, command=l.yview)
    l['yscrollcommand']=s.set
    s.pack(side='right', fill='y')

    startAddr=0
    # endAddr=eepromType.get()
    eeprom.sendcommand ('r', chip_id, startAddr, chip_endAddress)
    while (startAddr < chip_endAddress):
        bytesline='%05X:  ' % startAddr
        asciiline=' '
        i=16
        while(i):
            data=eeprom.read(1)
            if data:
                bytesline += '%02X ' % data[0]
                if (data[0] > 31) and data[0] < 127: asciiline += chr(data[0])
                else: asciiline += '.'
                i -= 1
        l.insert('end', bytesline + asciiline)
        startAddr += 16
    eeprom.readline()
    eeprom.close()

    contentWindow.mainloop()
    contentWindow.quit()



def uploadBin28():
    eeprom=Programmer()
    eeprom.connect340()
    if not eeprom.is_open:
        messagebox.showerror('Error', 'EEPROM Programmer not found !')
        return

    maxAddr=eepromType.get()
    startAddr=0

    fileName=filedialog.askopenfilename(title="Select binary file for upload", 
                filetypes=(("binary files", "*.bin"), ("all files", "*.*")))
    if not fileName:
        return

    try:
        f=open(fileName, 'rb')
    except:
        messagebox.showerror('Error', 'Could not open file !')
        eeprom.close()
        return

    fileSize=os.stat(fileName).st_size
    if (startAddr + fileSize) > (maxAddr + 1):
        messagebox.showerror('Error', 'Binary file doesn\'t fit into EEPROM !')
        f.close()
        eeprom.close()
        return

    progress=Progressbox(mainWindow, 'Please wait !', 'Writing data to EEPROM ...')

    # 28使用解锁芯片
    if chip_id.startswith('28'):
        eeprom.unlock()

    # 默认缓存 128
    buffer_length = 0x7f

    datalength=fileSize
    byteswritten=0
    addr1=startAddr
    while (datalength):
        count=(addr1 | buffer_length) - addr1 + 1
        if count > datalength:
            count=datalength
        addr2=addr1 + count - 1
        # 写一页数据64
        eeprom.sendcommand('p', chip_id, addr1, addr2) # 第一次地址 0-63
        eeprom.write(f.read(count))
        byteswritten += count
        progress.setvalue(byteswritten * 100 // fileSize)
        eeprom.readline()
        addr1 += count
        datalength -= count

    if chip_id.startswith('28'):
        eeprom.lock()

    progress.setactivity('Verifying written data ...')
    f.seek(0)
    endAddr=startAddr + byteswritten - 1
    count=byteswritten
    eeprom.sendcommand ('r', chip_id, startAddr, endAddr)

    while (count):
        data=eeprom.read(1)
        if data:
            if data != f.read(1):
                progress.close()
                messagebox.showerror('Error', 'Verification failed !')
                f.close()
                eeprom.close()
                return
            count -= 1
    eeprom.readline()

    f.close()
    eeprom.close()
    progress.destroy()
    messagebox.showinfo('Mission accomplished', 
                str(byteswritten) + ' bytes successfully written !')


def downloadBin28():
    eeprom=Programmer()
    eeprom.connect340()
    if not eeprom.is_open:
        messagebox.showerror('Error', 'EEPROM Programmer not found !')
        return

    startAddr=0
    # endAddr =eepromType.get()
    count   =chip_endAddress - startAddr + 1

    fileName=filedialog.asksaveasfilename(title="Select output file", 
                filetypes=(("binary files", "*.bin"), ("all files", "*.*")))
    if not fileName:
        return
    if not fileName.lower().endswith('.bin'):
        fileName = fileName+".bin"

    try:
        f=open(fileName, 'wb')
    except:
        messagebox.showerror('Error', 'Could not open file !')
        eeprom.close()
        return

    eeprom.sendcommand ('r', chip_id, startAddr, chip_endAddress)
    while (count):
        data=eeprom.read(1)
        if data:
            f.write(data)
            count -= 1
    eeprom.readline()
    f.close()
    eeprom.close()
    messagebox.showinfo('Mission accomplished', 'Download completed !')

def earse28():
    print("调用擦除")
    pass


def lock28():
    eeprom=Programmer()
    eeprom.connect340()
    if not eeprom.is_open:
        messagebox.showerror('Error', 'EEPROM Programmer not found !')
        return
    eeprom.unlock()
    eeprom.close()
    messagebox.showinfo('lock', 'lock !')
def unlock28():
    eeprom=Programmer()
    eeprom.connect340()
    if not eeprom.is_open:
        messagebox.showerror('Error', 'EEPROM Programmer not found !')
        return
    eeprom.unlock()
    eeprom.close()
    messagebox.showinfo('unlock', 'unlock !')


# ------------------------------------------------------------
def uploadBin():
    if chip_rw == 0:
        messagebox.showinfo('提示', '不支持写入')
        return

def downloadBin():

    pass
def earse():
    if chip_rw == 0:
        messagebox.showinfo('提示', '不支持写入')
        return


# ------------------------------------------------------------

# tkinter
mainWindow=Tk()
mainWindow.title(mainTitle)
screenWidth = mainWindow.winfo_screenwidth()   # 屏幕宽度
screenHeight = mainWindow.winfo_screenheight()  # 屏幕高度
w = 600
h = 500
x = (screenWidth - w) / 2
y = (screenHeight - h) / 2
mainWindow.geometry("%dx%d+%d+%d" % (w, h, x, y)) # 距离屏幕左上角(400, 200)
mainWindow.resizable(width=False, height=False)

# eepromType=IntVar()
eepromType=StringVar()
eepromType.set('2716')

#
def chips_selected():
    print("选择了:{}".format(eepromType.get()))

    global chip_id, chip_name, chip_rw, chip_endAddress
    chip_id = eepromType.get()
    for cp in chips:
        if cp[1] == chip_id:
            chip_name = cp[0]
            chip_endAddress = cp[2]
            chip_rw = cp[3]
            print("选择芯片: {} {}".format(chip_name,chip_rw))


# 默认选择 2716
chips_selected()

typeFrame=Frame(mainWindow, borderwidth=2, relief='groove')
Label(typeFrame, text='1. 选择芯片:').pack(pady=5, fill="x")

typeFrame24read=Frame(typeFrame, borderwidth=2, relief='groove')
Label(typeFrame24read, text='24脚(只读)').pack(pady=5)
for name, value,endAddress, readonly in radio27_24P:
    Radiobutton(typeFrame24read, text=name, variable=eepromType, value=value, command=chips_selected).pack(side="top")
typeFrame24read.pack(side="left", expand=True, fill=BOTH)

typeFrame28read=Frame(typeFrame, borderwidth=2, relief='groove')
Label(typeFrame28read, text='28脚(只读)').pack(pady=5)
for name, value,endAddress, readonly in radio27_28P:
    Radiobutton(typeFrame28read, text=name, variable=eepromType, value=value, command=chips_selected).pack(side="top")
typeFrame28read.pack(side="left", expand=True, fill=BOTH)

typeFrame28=Frame(typeFrame, borderwidth=2, relief='groove')
Label(typeFrame28, text='28脚').pack(pady=5)
for name, value,endAddress, readonly in radio28:
    Radiobutton(typeFrame28, text=name, variable=eepromType, value=value, command=chips_selected).pack(side="top")
typeFrame28.pack(side="left", expand=True, fill=BOTH)

typeFrame32=Frame(typeFrame, borderwidth=2, relief='groove')
Label(typeFrame32, text='32脚').pack(pady=5)
Label(typeFrame32, text='SST39、Amic、MX').pack(pady=5)
for name, value,endAddress, readonly in radio32:
    Radiobutton(typeFrame32, text=name, variable=eepromType, value=value, command=chips_selected).pack(side="top")
typeFrame32.pack(side="left", expand=True, fill=BOTH)

typeFrame32_other=Frame(typeFrame, borderwidth=2, relief='groove')
Label(typeFrame32_other, text='32脚(128字节写入)').pack(pady=5)
Label(typeFrame32_other, text='Winbond、AT、SST29').pack(pady=5)
for name, value,endAddress, readonly in radio32_page128:
    Radiobutton(typeFrame32_other, text=name, variable=eepromType, value=value, command=chips_selected).pack(side="top")
typeFrame32_other.pack(side="left", expand=True, fill=BOTH)

typeFrame.pack(padx=10, pady=10, ipadx=5, ipady=5, fill='x')

actionFrame=Frame(mainWindow, borderwidth=2, relief='groove')
Label(actionFrame, text='2. 选择操作:').pack(pady=5, fill="x")
Button(actionFrame, text='显示 EEPROM 内容', command=showContent).pack(side="left", expand=True, fill=BOTH)
Button(actionFrame, text='EEPROM 读取到文件', command=downloadBin).pack(side="left", expand=True, fill=BOTH)
Button(actionFrame, text='写入文件到 EEPROM', command=uploadBin).pack(side="left", expand=True, fill=BOTH)
Button(actionFrame, text='擦除芯片FF', command=earse).pack(side="left", expand=True, fill=BOTH)

# Button(actionFrame, text='Lock', command=lock28, width=8).pack()
# Button(actionFrame, text='解锁', command=unlock28, width=8).pack()

actionFrame.pack(padx=10, ipadx=5, ipady=5, fill='x')


Button(mainWindow, text='退出', command=mainWindow.quit).pack(pady=10)

mainWindow.mainloop()
